一列隊伍有長度,也有各式各樣不同的物種,這才有趣嘛!
length 這個屬性應該算是我們在學 Javascript 的初期,最早開始用的一個屬性,我們常常來用它來當作是跑字串或陣列的迴圈條件,但是,作為 Array 的唯一屬性 length 真的有這麼單純嗎?
我們可以從 Chrome 的開發工具的 console 裡,輸入window.Array.prototype
可以找到它。並試著了解它多一點。
先看一下 MDN 對它的定義:
作為 Array 類型的實例物件的 length 屬性,設置或回傳該陣列中的元素數。 該值是一個無符號的32位整數,其數值總是大於陣列中的最高索引。
嗯,解釋得很清楚,但好像單薄了點。果然,查找了「JavaScript 大全」的解釋,把 length 解釋得較為詳細,且還講到了密集陣列(dense)和稀疏陣列(sparse),其中更強調了無論是以上哪種型態的陣列,length 的長度不會等於或小於陣列的最大索引值,也就是說 length 會比陣列最大的索引值多 1。但有個例外,就是空陣列。 廢話
這個其實不難理解,在許多程式語言裡,陣列的索引值都是從 0 開始算起,當然 JavaScript 也不例外。JavaScript 的 length 是從 1 開始,從下面這張圖片可以看出為什麼長度總比索引值大的原因。
別看 length 這個屬性,好像只能知道陣列的長度,但是如果知道怎麼活用它,會發現它的功用還不少。接下來介紹是幾種 length 的用法:
只要在我們想知道的陣列變數,以方法的方式加上.length
。回傳回來的就是這個陣列的長度。
let arr = ["hi","ho","woops","ciao"];
console.log(arr.length); // 4
這的確是個快速清空的方法,但是陣列在 JavaScript 裡,骨子裡是物件,也就是在記憶體裡,當我們宣告它時,也同時記錄了它在記憶體的位置(call by reference),而如果我們複製了這個陣列,然後用 length 這個屬性去操控它,嗯,恩湯喔,很危險,同時會指向來源陣列,所以也會修改來源陣列。
這個codepen 有更詳細的範例說明,記得只觀察比對 JS 和 console(在左下角)的部分。
let say = ["hi","ho","woops","ciao"];
say.length = 0;
console.log(say) // []
上面範例中的say.length = 0;
也可以用say.length = [];
取代,效果一樣,原因是 JavaScript 會把[]
轉成數字型別的0
Number([]) // 0
除了可以用 JavaScript 的內建函式 pop();
去提取陣列的最後一個元素外,還可以用下面這種方法。找到陣列中最後一個值, 把 length 的長度減掉 1 再把它對應到索引值,就是陣列的最後一個了。
let say = ["hi","ho","woops","ciao"];
let lastSay = say[say.length-1];
console.log(lastSay) // ciao
直接把原本的陣列長度,用指派的方式減掉最後一個陣列元素。
let say = ["hi","ho","woops","ciao"];
say.length = say.length-1;
console.log(say) // ["hi", "ho", "woops"]
如果要在陣列尾部增加一個元素,除了可以用 JavaScript 的內建函式 push();
去增加外,還可以用這種方法增加,真的很奇妙!
let say = ["hi","ho","woops","ciao"];
say[say.length] = "haha";
console.log(say) // ["hi", "ho", "woops", "ciao", "haha"]
這是我們常用的方法,把迴圈限制在陣列的長度範圍內,跑完陣列的長度自動停止,真的很方便。以下的範例就是計算陣列裡面元素的總和。
let nbr = [2, 4, 6, 8];
let sum = 0
for (let i = 0; i < nbr.length; i++) {
sum = sum + nbr[i];
}
console.log(sum) // 20
雖然 length 可以這樣用,但並不表示就是好的方法,因為 length 是陣列的屬性,陣列在 JavaScript 是屬於非原始型別(Non-Primitive)也就是物件型別(Object type)與傳址(Pass by referance), 別緊張,這幾個名詞都是指同一件事情。 所以不可不慎用,一改動是會同時更動複製的原陣列的。
不知道這篇 length 的介紹,有沒有讓大家對它有另一種看法,程式的變化實在是太精采,但知道活用或許比知道原本的功能更重要吧?
透過鐵人賽寫文來查找資料,實在是個不錯的方法,人家說「當爸爸之後才學著怎麼當爸爸」,本人雖然無法當爸爸,但對這句話的涵義也頗有感觸,期望在這樣查找與發現的狀態下,多練些腦肌肉也是好的。
如有需要改進的地方,拜託懇求請告知,我會盡量快速度修改,感謝您~
先看一下 NDM 對它的定義 => MDN
把陣列清空第二種的部分,猜測你應該是想說:say = [];
而不是 say.length = [];
,因為後者其實就跟第一種一樣
歐~胡大,感謝,我的文字顛倒正又犯了,已改正。
say = [];
和say.length = [];
看似結果一樣,但應該是不一樣,要有複製才看得出來。其實我也很疑惑,JS 也接受say.length = [];
這樣的寫法。
我做實驗的結果(下面這個範例的第三個)
https://codepen.io/tsuifei/pen/zYOMRKa?editors=0012say = []
會將一個新陣列重新指派給say
但是say.length = [];
會把原本依樣位址的資料清空,但是因為是指向同一個位址,所以如果從say複製過來的也會清空。
不知道我有沒有理解錯誤....
我說的一樣指的是 say.length = [];
跟「文章裡面提的第一種」say.length = 0;
一樣,我猜 JS 最終會把 []
轉型成 0 之類的(不確定,純猜測),所以我才說一樣。
所以我才說你文章裡面提的這兩種其實是一樣的,原理都是把 length 設定成 0。然後想說會不會你第二種想提的其實是 say = [];
只是打錯程式碼。
啊~了解,那我來改一下,
我們家ruru找了大全來看,在P46有寫型別轉換,的確剛剛測試Number([])
會回傳 0 耶~
看完這篇真的收穫滿滿 ❤
@ Ruru 好險妳在我旁邊讓我問,我們一起來把大全用爛吧,哈哈!